/* Microsoft Reference Implementation for TPM 2.0
 *
 *  The copyright in this software is being made available under the BSD License,
 *  included below. This software may be subject to other third party and
 *  contributor rights, including patent rights, and no such rights are granted
 *  under this license.
 *
 *  Copyright (c) Microsoft Corporation
 *
 *  All rights reserved.
 *
 *  BSD License
 *
 *  Redistribution and use in source and binary forms, with or without modification,
 *  are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice, this list
 *  of conditions and the following disclaimer.
 *
 *  Redistributions in binary form must reproduce the above copyright notice, this
 *  list of conditions and the following disclaimer in the documentation and/or
 *  other materials provided with the distribution.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ""AS IS""
 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 *  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 *  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 *  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 *  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#include "Tpm.h"
#include "PolicyOR_fp.h"

#if CC_PolicyOR  // Conditional expansion of this file

#include "Policy_spt_fp.h"

/*(See part 3 specification)
// PolicyOR command
*/
//  Return Type: TPM_RC
//      TPM_RC_VALUE            no digest in 'pHashList' matched the current
//                              value of policyDigest for 'policySession'

/*
tpm2_policyor(1) - Generates a policy_or event with the TPM. It expects a session to be already established via tpm2_startauthsession(1). 
If the input session is a trial session this tool generates a policy digest that compounds two or more input policy digests such that the 
resulting policy digest requires at least one of the policy events being true. 
If the input session is real policy session tpm2_policyor(1) authenticates the object successfully if at least one of the policy events are true.
Tpm2_policyor(1)-使用 TPM 生成 policy_or 事件。它期望通过 tpm2_startauthsession(1)已经建立一个会话。如果输入会话是一个试用会话，这个工具将生成一个策略摘要，
该策略摘要将两个或多个输入策略摘要合并在一起，以便生成的策略摘要要求至少一个策略事件为真。如果输入会话是真正的策略会话，tpm2_policyor(1)将成功验证对象(如果至少有一个策略事件为 true)。


This command allows options in authorizations without requiring that the TPM evaluate all of the options.
If a policy may be satisfied by different sets of conditions, the TPM need only evaluate one set that satisfies the policy. 
This command will indicate that one of the required sets of conditions has been satisfied.
PolicySession→policyDigest is compared against the list of provided values. If the current policySession→policyDigest does 
not match any value in the list, the TPM shall return TPM_RC_VALUE.
Otherwise, the TPM will reset policySession→policyDigest to a Zero Digest. Then policySession→policyDigest is extended by the 
concatenation of TPM_CC_PolicyOR and the concatenation of all of the digests.

此命令允许授权中的选项，而不需要 TPM 评估所有选项。
如果一个策略可以通过不同的条件集来满足，TPM 只需要评估一组满足该策略的条件。 此命令将指示已满足所需的一组条件。
PolicySession→policyDigest 与提供的值列表进行比较。 如果当前的 policySession→policyDigest 不匹配列表中的任何值，TPM 将返回 TPM_RC_VALUE。
否则，TPM 会将 policySession→policyDigest 重置为零摘要。 然后通过 TPM_CC_PolicyOR 的串联和所有摘要的串联扩展 policySession→policyDigest。


TPM2_PolicyOR 策略并不会计算多个参与或运算参数从而生成多个 digest.
在试用策略中，根据如下公式：
digests ≔ pHashList.digests[1].buffer || … || pHashList.digests[n].buffer
policyDigestnew ≔ HpolicyAlg(0…0 || TPM_CC_PolicyOR || digests)
生成了新的 digest 值，而 0…0 表示 session 原有的digest被设置为全零。

使用时，对于 OR 策略，要单独使用一个 session，先计算出一个 digest 值，在使用 TPM2_PolicyOR(包含所有可能的 digestlist)，来检查 digest 是否在 digestlist 中
如果满足，说明符合 OR 策略的某个条件，从而你生成一个新的 digest，公式仍然是上面的公式。
如果策略还未完，则继续更新，如果结束，就是用 TPM2_PolicyOR 得到的 digest.

*/
TPM_RC
TPM2_PolicyOR(
    PolicyOR_In     *in             // IN: input parameter list
    )
{
    SESSION     *session;
    UINT32       i;

// Input Validation and Update

    // Get pointer to the session structure
    session = SessionGet(in->policySession);

    // Compare and Update Internal Session policy if match
    for(i = 0; i < in->pHashList.count; i++)
    {
        if(session->attributes.isTrialPolicy == SET
           || (MemoryEqual2B(&session->u2.policyDigest.b,
                             &in->pHashList.digests[i].b)))
        {
            // Found a match
            HASH_STATE      hashState;
            TPM_CC          commandCode = TPM_CC_PolicyOR;

            // Start hash
            session->u2.policyDigest.t.size
                = CryptHashStart(&hashState, session->authHashAlg);
            // Set policyDigest to 0 string and add it to hash
            MemorySet(session->u2.policyDigest.t.buffer, 0,
                      session->u2.policyDigest.t.size);
            CryptDigestUpdate2B(&hashState, &session->u2.policyDigest.b);

            // add command code
            CryptDigestUpdateInt(&hashState, sizeof(TPM_CC), commandCode);

            // Add each of the hashes in the list
            for(i = 0; i < in->pHashList.count; i++)
            {
                // Extend policyDigest
                CryptDigestUpdate2B(&hashState, &in->pHashList.digests[i].b);
            }
            // Complete digest
            CryptHashEnd2B(&hashState, &session->u2.policyDigest.b);

            return TPM_RC_SUCCESS;
        }
    }
    // None of the values in the list matched the current policyDigest
    return TPM_RCS_VALUE + RC_PolicyOR_pHashList;
}

#endif // CC_PolicyOR